from datetime import datetime, timedelta
from typing import Optional, List
import jwt
from jwt import InvalidTokenError
from passlib.context import CryptContext
from fastapi import HTTPException, status, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session
import hashlib

from database.database import User, Role, Permission, UserToken
from database.database_function import get_db

# JWT配置
SECRET_KEY = "your-secret-key-here-change-this-in-production"  # 在生产环境中应该使用环境变量
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7  # 7天

# 密码加密
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# HTTP Bearer token认证
security = HTTPBearer(auto_error=False)  # 设置为False以支持可选认证


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """验证密码"""
    return pwd_context.verify(plain_password, hashed_password)


def get_password_hash(password: str) -> str:
    """获取密码哈希"""
    return pwd_context.hash(password)


def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    """创建JWT token"""
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt, expire


def authenticate_user(db: Session, username: str, password: str) -> Optional[User]:
    """验证用户身份"""
    user = db.query(User).filter(User.username == username, User.is_active == True).first()
    if not user:
        return None
    if not verify_password(password, user.password_hash):
        return None
    return user


def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db)) -> User:
    """获取当前用户"""
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效的认证凭据",
        headers={"WWW-Authenticate": "Bearer"},
    )
    
    if not credentials:
        print("DEBUG: No credentials provided")
        raise credentials_exception
    
    try:
        print(f"DEBUG: Decoding token: {credentials.credentials[:50]}...")
        payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
        user_id: str = payload.get("sub")
        print(f"DEBUG: Extracted user_id: {user_id}")
        if user_id is None:
            print("DEBUG: No user_id in token")
            raise credentials_exception
    except InvalidTokenError as e:
        print(f"DEBUG: JWT decode error: {e}")
        raise credentials_exception
    
    # 暂时跳过数据库token检查，只验证JWT和用户存在性
    user = db.query(User).filter(User.user_id == int(user_id), User.is_active == True).first()
    if user is None:
        print(f"DEBUG: User not found or inactive: {user_id}")
        raise credentials_exception
    
    print(f"DEBUG: User authenticated: {user.username}")
    return user


def get_current_active_user(current_user: User = Depends(get_current_user)) -> User:
    """获取当前活跃用户"""
    if not current_user.is_active:
        raise HTTPException(status_code=400, detail="用户已被禁用")
    return current_user


def get_user_permissions(db: Session, user: User) -> List[str]:
    """获取用户权限列表"""
    permissions = db.query(Permission).join(
        Role.permissions
    ).filter(Role.role_id == user.role_id).all()
    return [perm.permission_name for perm in permissions]


def require_permission(permission_name: str):
    """权限装饰器"""
    def permission_dependency(
        current_user: User = Depends(get_current_active_user),
        db: Session = Depends(get_db)
    ):
        user_permissions = get_user_permissions(db, current_user)
        if permission_name not in user_permissions:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail=f"缺少权限: {permission_name}"
            )
        return current_user
    
    return permission_dependency


def get_token_hash(token: str) -> str:
    """获取token的哈希值"""
    return hashlib.sha256(token.encode()).hexdigest()


def save_user_token(db: Session, user_id: int, token: str, expires_at: datetime):
    """保存用户token到数据库"""
    token_hash = get_token_hash(token)
    user_token = UserToken(
        user_id=user_id,
        token_hash=token_hash,
        expires_at=expires_at
    )
    db.add(user_token)
    db.commit()


def revoke_user_token(db: Session, token: str):
    """撤销用户token"""
    token_hash = get_token_hash(token)
    user_token = db.query(UserToken).filter(UserToken.token_hash == token_hash).first()
    if user_token:
        user_token.is_active = False
        db.commit()


# 可选的用户依赖（不强制登录）
def get_optional_user(credentials: Optional[HTTPAuthorizationCredentials] = Depends(security), db: Session = Depends(get_db)) -> Optional[User]:
    """获取可选的当前用户（允许匿名访问）"""
    if not credentials:
        return None
    
    try:
        payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=[ALGORITHM])
        user_id: str = payload.get("sub")
        if user_id is None:
            return None
    except InvalidTokenError:
        return None
    
    # 检查token是否在数据库中存在且有效
    token_hash = get_token_hash(credentials.credentials)
    user_token = db.query(UserToken).filter(
        UserToken.token_hash == token_hash,
        UserToken.is_active == True,
        UserToken.expires_at > datetime.utcnow()
    ).first()
    
    if not user_token:
        return None
    
    user = db.query(User).filter(User.user_id == int(user_id), User.is_active == True).first()
    return user 